
#include <BReadWrite>
#include <BMovie>
#include "member_BMovie.h"
#include "member_BImage.h"
#include "member_BTexture.h"
#include "IGlobal.h"

using namespace BWE;

#define member					(*(member_BMovie*)_ptr)
#define member_allocate()		_ptr = new member_BMovie(this)
#define member_release()		delete (member_BMovie*)_ptr

BMovie::BMovie()
{
	member_allocate();
	app_movies.append(this);
}
BMovie::BMovie(const BString& fileName)
{
	member_allocate();
	if (ReadFile(fileName, this))
	{
		image_member(this)->fileName = fileName;
	}
	app_movies.append(this);
}
BMovie::BMovie(Format format) : BImage(format)
{
	member_allocate();
	app_movies.append(this);
}
BMovie::BMovie(const BSize& size, Format format) : BImage(size, format)
{
	member_allocate();
	app_movies.append(this);
}
BMovie::BMovie(int width, int height, Format format) : BImage(width, height, format)
{
	member_allocate();
	app_movies.append(this);
}
BMovie::BMovie(const BMovie& other)
{
	member_allocate();
	app_movies.append(this);
}
BMovie::~BMovie()
{
	member_release();
	app_movies.remove(this);
}

void BMovie::copy(const BTexture* other)
{
	BImage::copy(other);
	if (const BMovie* movie = dynamic_cast<const BMovie*>(other))
	{
		member.current = movie_member(movie)->current;
		member.tick = movie_member(movie)->tick;
		member.duration = movie_member(movie)->duration;
		member.speed = movie_member(movie)->speed;
		member.loop = movie_member(movie)->loop;
		member.paused = movie_member(movie)->paused;
		member.dirty = movie_member(movie)->dirty;
		member.pixelsArray = movie_member(movie)->pixelsArray;
	}
}
BImage* BMovie::clone() const
{
	BMovie* movie = new BMovie();
	movie->copy(this);
	return movie;
}

bool BMovie::addFrame(const BByteArray& pixels)
{
	if (member.pixelsArray.append(pixels))
	{
		this->emit(Signal_Dirty);
		return true;
	}
	return false;
}
bool BMovie::setFrame(int pos, const BByteArray& pixels)
{
	if (member.pixelsArray.set(pos, pixels))
	{
		this->emit(Signal_Dirty);
		return true;
	}
	return false;
}
bool BMovie::insertFrame(int pos, const BByteArray& pixels)
{
	if (member.pixelsArray.insert(pos, pixels))
	{
		this->emit(Signal_Dirty);
		return true;
	}
	return false;
}
bool BMovie::removeFrame(int index)
{
	if (member.pixelsArray.remove(index))
	{
		this->emit(Signal_Dirty);
		return true;
	}
	return false;
}

int BMovie::frameCount() const
{
	return member.pixelsArray.size();
}
BByteArray& BMovie::frame(int index)
{
	return member.pixelsArray(index);
}
const BByteArray& BMovie::frame(int index) const
{
	return member.pixelsArray(index);
}

void BMovie::setCurrent(int current)
{
	if (member.current != current)
	{
		member.current = current;
		member.dirty = false;
		*image_member(this)->pixels = member.pixelsArray[member.current];
		image_member(this)->dirty = true;
		texture_member(this)->dirty = true;
		emit(Signal_Dirty);
	}
}
int BMovie::current() const
{
	return member.current;
}

void BMovie::setDuration(BReal duration)
{
	if (member.duration != duration)
	{
		member.duration = duration;
		this->emit(Signal_Changed);
		this->dirty();
	}
}
BReal BMovie::duration() const
{
	return member.duration;
}

bool BMovie::setSpeed(int speed)
{
	if (member.speed != speed)
	{
		member.speed = speed;
		this->emit(Signal_Changed);
		return true;
	}
	return false;
}
int BMovie::speed() const
{
	return member.speed;
}

void BMovie::setLoop(bool loop)
{
	if (member.loop != loop)
	{
		member.loop = loop;
		this->emit(Signal_Changed);
	}
}
bool BMovie::loop() const
{
	return member.loop;
}

bool BMovie::start()
{
	if (member.paused == true)
	{
		member.paused = false;
		this->emit(Signal_StateChanged, !member.paused);
	}
	return true;
}
bool BMovie::pause()
{
	if (member.paused == false)
	{
		member.paused = true;
		this->emit(Signal_StateChanged, !member.paused);
	}
	return true;
}
bool BMovie::stop()
{
	if (member.paused == false)
	{
		member.paused = true;
		member.current = 0;
		this->emit(Signal_StateChanged, !member.paused);
	}
	return true;
}

bool BMovie::paused() const
{
	return member.paused;
}

bool BMovie::flush() const
{
	if (member.dirty && image_member(this)->pixels)
	{
		member.dirty = false;
		BByte* data0 = image_member(this)->pixels->data();
		BByte* data1 = member.pixelsArray[member.current].data();
		memcpy(data0, data1, this->pixels()->size());
		image_member(this)->dirty = true;
		this->emit(Signal_Flushed);
	}
	BImage::flush();	
	return true;
}
